package game.assets;

import hx.assets.Assets;
import hx.core.OpenFlBitmapData;
import game.data.IRoleData;
import game.data.ProjectRoleData;
import haxe.io.Bytes;
import haxe.io.BytesInput;
import haxe.io.Path;
import hx.assets.Atlas;
import hx.assets.BytesFuture;
import hx.assets.Future;
import hx.assets.Sound;
import hx.assets.XmlAtlas;
import hx.core.OpenFLSound;
import hx.display.BitmapData;
import hx.events.FutureErrorEvent;
import lime._internal.format.Deflate;
import openfl.errors.IOError;
import openfl.events.Event;
import openfl.events.IOErrorEvent;

using game.utils.StringsTools;

/**
 * 加载`.abn`人物格式文件
 */
class ABNDataFuture extends Future<RoleAssets, String> {
	public function new(path:String) {
		super(path, false);
	}

	override function post() {
		super.post();
		// 先加载二进制文件abn
		new BytesFuture(this.path).onComplete(bytes -> {
			// 解压文件
			var assets = new RoleAssets();
			var bytesInput = new BytesInput(bytes);
			var abporjId = Path.withoutExtension(Path.withoutDirectory(path)) + ".abproj";
			var roleData:ProjectRoleData = null;
			var entrys:Map<String, {
				ext:String,
				data:Bytes
			}> = [];
			while (bytesInput.position < bytesInput.length) {
				var nameLen = bytesInput.readInt32();
				var name = Path.withoutDirectory(bytesInput.readString(nameLen));
				var ext = Path.extension(name);
				var dataLen = bytesInput.readInt32();
				var data = Deflate.decompress(bytesInput.read(dataLen));
				entrys.set(name, {
					ext: ext,
					data: data
				});
				if (ext == "hx") {
					assets.strings.set(Path.withoutDirectory(Path.withoutExtension(name)), data.toString());
				}
				if (ext == "abproj") {
					assets.roleDatas.set(Path.withoutExtension(name), new ProjectRoleData(data.toString()));
				}
			}

			// roleData = new ProjectRoleData(entrys.get(abporjId).data.toString());
			assets.id = Path.withoutExtension(abporjId);
			roleData = cast assets.roleDatas.get(assets.id);
			// var files = roleData.getAssetsFiles();
			var files = [];
			for (data in assets.roleDatas) {
				cast(data, ProjectRoleData).getAssetsFiles(files);
			}
			for (file in files) {
				switch file.type {
					case ATLAS:
						assets.pushFuture(new ABNDataBitmapDataAtlasFuture({
							path: file.path,
							data: entrys.get(file.path).data,
							xml: entrys.get(Path.withoutExtension(file.path) + ".xml").data.toString()
						}));
					case SOUND:
						assets.pushFuture(new ABNDataSoundFuture({
							path: file.path,
							data: entrys.get(file.path).data
						}));
				}
			}

			assets.onComplete(a -> {
				assets.data = roleData;
				this.completeValue(assets);
			}).onError(this.errorValue);
			assets.start();
		}).onError(this.errorValue);
	}
}

class ABNDataSoundFuture extends Future<Sound, {
	path:String,
	data:Bytes
}> {
	override function post() {
		super.post();
		var sound = new openfl.media.Sound();
		sound.addEventListener(Event.COMPLETE, (e) -> {
			var s = new Sound();
			s.root = new OpenFLSound(sound);
			this.completeValue(s);
		});
		sound.addEventListener(IOErrorEvent.IO_ERROR, (e) -> {
			this.errorValue(new FutureErrorEvent(FutureErrorEvent.LOAD_ERROR));
		});
		sound.loadCompressedDataFromByteArray(this.getLoadData().data, this.getLoadData().data.length);
	}
}

class ABNDataBitmapDataAtlasFuture extends Future<Atlas, {
	path:String,
	data:Bytes,
	xml:String
}> {
	override function post() {
		super.post();
		openfl.display.BitmapData.loadFromBytes(this.getLoadData().data).onComplete(bitmapData -> {
			var atlas = new XmlAtlas(OpenFlBitmapData.fromBitmapData(bitmapData), Xml.parse(this.getLoadData().xml));
			this.completeValue(atlas);
		}).onError((err) -> {
			this.errorValue(new FutureErrorEvent(FutureErrorEvent.LOAD_ERROR));
		});
	}
}
